#include <iostream>
#include <sstream>
#include <string>
#include <assert.h>
#include "status.hxx"
#include "util/fs.hxx"
#include "util/io.hxx"

std::string path;

PosixMmapSequentialWriter* w = NULL;
PosixSequentialReader* r = NULL;

void init() {
    DbStatus ret;

    w = new PosixMmapSequentialWriter(path, getpagesize(), 1024);
    ret = w->init();
    if(!ret.isok()) {std::cout<<ret.msg()<<"\n";return;}

    r = new PosixSequentialReader(path);
    ret = r->init();
    if(!ret.isok()) {std::cout<<ret.msg()<<"\n";return;}    
}

void clean() {
    DbStatus ret;

    ret = FsUtility::deleteFile(path);
    if(!ret.isok()) {std::cout<<"clean file: "<<ret.msg()<<"\n";return;}

    delete w; delete r;
    w = NULL; r = NULL;
}

//small record, write n records
int testSmallWrite(int n) {
    DbStatus ret;

    init();    

    int totalSize = 0;
    std::string result;

    //write
    for(int i = 0; i < n; ++i) {
        std::ostringstream oss;
        oss<<i;
        totalSize += oss.str().size();
        result += oss.str();

        ret = w->append(oss.str());
        if(!ret.isok()) {std::cout<<ret.msg()<<"\n";return -1;}
    }
    w->flush();

    //read
    ret = r->skip(1024);
    if(!ret.isok()) {std::cout<<ret.msg()<<"\n";return -1;}
  
    std::string str;
    ret = r->read(totalSize, str);

    assert(result == str);

    w->close();

    uint64_t filesize; FsUtility::getFileSize(path, filesize);
    assert(filesize == 1024+totalSize);

    clean();

    return 0;
}

//big record, write n records
int testBigWrite(int n) { 
    DbStatus ret;

    init();

    int totalSize = 0;
    std::string result;

    std::string data("123456");
    //write
    for(int i = 0; i < n; ++i) {
        std::ostringstream oss;
        oss<<i;
        for(int j = 0; j < 10000; ++j) oss<<data;
        totalSize += oss.str().size();
        result += oss.str();

        ret = w->append(oss.str());
        if(!ret.isok()) {std::cout<<ret.msg()<<"\n";return -1;}
    }
    w->flush();

    //read
    ret = r->skip(1024);
    if(!ret.isok()) {std::cout<<ret.msg()<<"\n";return -1;}

    std::string str;
    ret = r->read(totalSize, str);

    assert(result == str);

    w->close();
    uint64_t filesize; FsUtility::getFileSize(path, filesize);
    assert(filesize == 1024+totalSize);

    clean();
    return 0;

}
    
void runAllTests() {
    for(int i = 0; i < 100; ++i) {
        int ret = testSmallWrite(i+1);
        if(ret != 0) {
            std::cout<<"testSmallWrite "<<i<<" fail\n";
         }   
    }

    for(int i = 0; i < 10; ++i) {
        int ret = testBigWrite(i+1);
        if(ret != 0) { 
            std::cout<<"testBigWrite "<<i<<" fail\n";
        }
    }
}

int main(int argc, char** argv) {

    path = std::string(argv[1]);
    runAllTests();
}

